﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Office.Interop.Excel;
using Thanhlichtek.BOS.Bullhorn;
using Thanhlichtek.BOS.Bullhorn.BullhornApi;
using System.Collections;
using System.IO;
using System.Xml;
using System.Threading;

namespace Thanhlichtek.BEF.Fix
{
    public class FixManager
    {
        //new
        public IList BullhornAccounts;
        public List<BullhornAccountFixInfo> BullhornAccountSyncInfos { get; set; }

        private const String _bullhornAccountsFile = "Profile\\BullhornAccounts.xml";
        private const int maxTry = 5;
        private List<EmailInfo> _emailInfos; 
        //end new

        public Account bullhornAccountItem;
        public List<distributionListDto> BullhornLists;
        public distributionListDto BullhornList;
        public clientContactDto ClientContact;



        public event EventHandler ConnectingStart;
        public event EventHandler ConnectingStop;
        public event EventHandler GettingBullhornListsStart;
        public event EventHandler GettingBullhornListsStop; 
        public event EventHandler GettingBullhornListInfoStart;
        public event EventHandler GettingBullhornListInfoStop;
        public event EventHandler FixListStart;
        public event EventHandler FixListStop;
        public event EventHandler FixStart;
        public event EventHandler SyncStop;
        public event EventHandler GetClientContactIdsStart;
        public event EventHandler GetClientContactIdsStop;
        public event EventHandler FixContactSuccess;
        public event EventHandler FixContactFail;
        public event EventHandler FixContactIgnore;
        public event EventHandler FixContactsStart;
        public event EventHandler SyncContactsStop;
        public event EventHandler FixError;


        public FixManager()
        {
            //Get Bullhorn accounts
            System.Xml.Serialization.XmlSerializer x2 = new System.Xml.Serialization.XmlSerializer(typeof(List<Account>));
            if (File.Exists(_bullhornAccountsFile))
            {
                XmlReader xr = XmlReader.Create(_bullhornAccountsFile);
                this.BullhornAccounts = (IList)x2.Deserialize(xr);
                xr.Close();
                foreach (var bullhornAccountObj in this.BullhornAccounts)
                {
                    ((Account)bullhornAccountObj).Password = CryptoHelper.Decrypt(((Account)bullhornAccountObj).Password);
                    ((Account)bullhornAccountObj).ApiKey = CryptoHelper.Decrypt(((Account)bullhornAccountObj).ApiKey);
                }
            }


        }

        public void GetBullhornListInfoDict(BullhornService bullhornService, BullhornAccountFixInfo bullhornAccountSyncInfo)
        {
            if (GettingBullhornListsStart != null)
            {
                this.GettingBullhornListsStart(this, EventArgs.Empty);
            }
            var listIds = bullhornService.GetListIds();
            var count = 0;
            foreach (var listIdObj in listIds)
            {
                count++;
                //hai test: limit the number of lists
                //if (count > 1) break;
                int listId = Int32.Parse(listIdObj.ToString());
                if (GettingBullhornListInfoStart != null)
                {
                    this.GettingBullhornListInfoStart(this, new FixEventArgs(String.Format("Getting Bullhorn lists ({0}/{1})", count, listIds.Count())));
                }
                var distributionList = bullhornService.GetListInfo(listId);
                var bullhornListInfo = new BullhornListInfo(bullhornAccountSyncInfo, distributionList);
                bullhornListInfo.CorporateUser = bullhornService.GetCorporateUser(distributionList.ownerID);
                bullhornAccountSyncInfo.BullhornListInfoDict.Add(listId, bullhornListInfo);
            }

            if (GettingBullhornListsStop != null)
            {
                this.GettingBullhornListsStop(this, new FixEventArgs() { BullhornAccountFixInfoObj = bullhornAccountSyncInfo});
            }
            
        }

        FixListThread fixListThread;

        public void StopSyncList()
        {
            try
            {
                fixListThread.StopAllThreads();

            }
            catch (Exception)
            {
                
                //throw;
            }
        }

        private List<EmailInfo> ReadExcelFile(string filePath)
        {
            var emailInfos = new List<EmailInfo>();

            Microsoft.Office.Interop.Excel.Application app = new Microsoft.Office.Interop.Excel.Application();

            Microsoft.Office.Interop.Excel.Workbook wb = app.Workbooks.Open(filePath, Type.Missing, Type.Missing, Type.Missing, Type.Missing,
                    Type.Missing, Type.Missing, Type.Missing, Type.Missing,
                    Type.Missing, Type.Missing, Type.Missing, Type.Missing,
                    Type.Missing, Type.Missing);

            Worksheet sheet = (Worksheet)wb.Sheets["Sheet1"];

            Range excelRange = sheet.UsedRange;

            foreach (Microsoft.Office.Interop.Excel.Range row in excelRange.Rows)
            {
                int rowNumber = row.Row;
                if (rowNumber > 1)
                {
                    string[] A4D4 = GetRange("A" + rowNumber + ":E" + rowNumber + "", sheet);
                    var emailInfoObj = new EmailInfo()
                                           {
                                               FirstName = A4D4[0],
                                               LastName = A4D4[1],
                                               OrgEmail = A4D4[2],
                                               FixedEmail = A4D4[3],
                                               ListName = A4D4[4]
                                           };
                    emailInfos.Add(emailInfoObj);
                }


            }

            return emailInfos;
        }

        public string[] GetRange(string range, Worksheet excelWorksheet)
        {
            Microsoft.Office.Interop.Excel.Range workingRangeCells =
              excelWorksheet.get_Range(range, Type.Missing);
            //workingRangeCells.Select();

            System.Array array = (System.Array)workingRangeCells.Cells.Value2;
            string[] arrayS = new string[array.Length];
            var arrayEnum = array.GetEnumerator();
            int i = 0;
            while (arrayEnum.MoveNext())
            {
                arrayS[i] = arrayEnum.Current.ToString();
                i++;
            }

            return arrayS;
        }

        public void StartFixing()
        {
            _emailInfos = ReadExcelFile(@"d:\CorrectedEmailsOn_20140114_122602.xlsx");
            var message = "Idle";
            try
            {
                foreach (var bullhornAccountObj in BullhornAccounts)
                {
                    message = "Idle";
                    bullhornAccountItem = (Account)bullhornAccountObj;
                    BullhornAccountFixInfo bullhornAccountFixInfo = new BullhornAccountFixInfo(bullhornAccountItem);


                    if (FixStart != null)
                    {
                        this.FixStart(this, new FixEventArgs("Start fixing"));
                    }

                    if (ConnectingStart != null)
                    {
                        this.ConnectingStart(this, new FixEventArgs("Connecting ..."));
                    }
                    BullhornService bullhornService;
                    try
                    {
                        bullhornService = new BullhornService(bullhornAccountItem.UserName,
                            bullhornAccountItem.Password, bullhornAccountItem.ApiKey, true);
                    }
                    catch (Exception)
                    {
                        throw new UnauthorizedAccessException("Please check your Bullhorn user name and password.");
                    }
                    if (ConnectingStop != null)
                    {
                        this.ConnectingStop(this, new FixEventArgs("Connected"));
                    }

                    //get Bullhorn lists
                    this.GetBullhornListInfoDict(bullhornService, bullhornAccountFixInfo);

                    var count = 0;
                    foreach (var bullhornListInfoItem in bullhornAccountFixInfo.BullhornListInfoDict.Values)
                    {
                        count++;
                        fixListThread = new FixListThread() { FixManagerObj = this, _BullhornListInfo = bullhornListInfoItem};
                        fixListThread.FixList();
                    }
                }


            }
            catch (Exception ex)
            {

                if (FixError != null)
                {
                    this.FixError(this, new FixEventArgs(ex.Message));
                }
            }
            finally
            {
                if (SyncStop != null)
                {
                    this.SyncStop(this, new FixEventArgs(message));
                }
            }
        }

        class FixListThread
        {
            private BullhornService _threadBullhornService;
            public BullhornListInfo _BullhornListInfo { get; set; }
            public FixManager FixManagerObj { get; set; }

            Thread accountThread1;
            Thread accountThread2;
            Thread accountThread3;
            Thread accountThread4;
            Thread accountThread5;
            Thread accountThread6;
            Thread accountThread7;
            Thread accountThread8;
            Thread accountThread9;
            Thread accountThread10;

            public void StopAllThreads()
            {
                try
                {
                    accountThread1.Abort();
                }
                catch (Exception)
                {
                    //throw;
                }
                try
                {
                    accountThread2.Abort();
                }
                catch (Exception)
                {
                    //throw;
                }
                try
                {
                    accountThread3.Abort();
                }
                catch (Exception)
                {
                    //throw;
                }
                try
                {
                    accountThread4.Abort();
                }
                catch (Exception)
                {
                    //throw;
                }
                try
                {
                    accountThread5.Abort();
                }
                catch (Exception)
                {
                    //throw;
                }
                try
                {
                    accountThread6.Abort();
                }
                catch (Exception)
                {
                    //throw;
                }
                try
                {
                    accountThread7.Abort();
                }
                catch (Exception)
                {
                    //throw;
                }
                try
                {
                    accountThread8.Abort();
                }
                catch (Exception)
                {
                    //throw;
                }
                try
                {
                    accountThread9.Abort();
                }
                catch (Exception)
                {
                    //throw;
                }
                try
                {
                    accountThread10.Abort();
                }
                catch (Exception)
                {
                    //throw;
                }
            }

            public void FixList()
            {
                _threadBullhornService = new BullhornService(_BullhornListInfo.BullhornAccountFixInfoObj.BullhornAccount.UserName, 
                    _BullhornListInfo.BullhornAccountFixInfoObj.BullhornAccount.Password,
                    _BullhornListInfo.BullhornAccountFixInfoObj.BullhornAccount.ApiKey, false);

                distributionListDto bullhornList = _BullhornListInfo.DistributionList;

                if (!FixManagerObj._emailInfos.Any(x => x.ListName == bullhornList.name))
                {
                    return;
                }

                if (FixManagerObj.GetClientContactIdsStart != null)
                {
                    FixManagerObj.GetClientContactIdsStart(FixManagerObj, new FixEventArgs(String.Format("Getting number of client contacts of {0} list ...", bullhornList.name)));
                }

                //get Bullhorn client contact ids
                var clientContactIds = _threadBullhornService.GetClientContactIds(bullhornList);

                if (clientContactIds != null)
                {
                    var count = 0;
                    _BullhornListInfo.ClientContactInfoDict = new Dictionary<int, ClientContactInfo>();
                    foreach (var clientContactId in clientContactIds)
                    {
                        count++;
                        //hai test: limit the number of client contact
                        //if (count > 2000) break;

                        _BullhornListInfo.ClientContactInfoDict.Add(Int32.Parse(clientContactId.ToString()), 
                            new ClientContactInfo() { BullhornListInfoObj = _BullhornListInfo, ClientContact = null, State = FixState.NotFixed, Message = "Pending" });
                    }

                }
                if (FixManagerObj.GetClientContactIdsStop != null)
                {
                    FixManagerObj.GetClientContactIdsStop(FixManagerObj, new FixEventArgs() { BullhornListInfoObj = _BullhornListInfo });
                }


                if (FixManagerObj.FixContactsStart != null)
                {
                    FixManagerObj.FixContactsStart(FixManagerObj, new FixEventArgs("Fixing emails of " + bullhornList.name));
                }

                //1
                FixAccountThread fixAccountThread1 = new FixAccountThread();
                fixAccountThread1._BullhornListInfo = _BullhornListInfo;
                fixAccountThread1.FixManagerObj = FixManagerObj;
                accountThread1 = new Thread(new ThreadStart(fixAccountThread1.FixAccount));
                accountThread1.IsBackground = true;
                accountThread1.Start();

                //2
                FixAccountThread fixAccountThread2 = new FixAccountThread();
                fixAccountThread2._BullhornListInfo = _BullhornListInfo;
                fixAccountThread2.FixManagerObj = FixManagerObj;
                accountThread2 = new Thread(new ThreadStart(fixAccountThread2.FixAccount));
                accountThread2.IsBackground = true;
                accountThread2.Start();

                //3
                FixAccountThread fixAccountThread3 = new FixAccountThread();
                fixAccountThread3._BullhornListInfo = _BullhornListInfo;
                fixAccountThread3.FixManagerObj = FixManagerObj;
                accountThread3 = new Thread(new ThreadStart(fixAccountThread3.FixAccount));
                accountThread3.IsBackground = true;
                accountThread3.Start();

                //4
                FixAccountThread fixAccountThread4 = new FixAccountThread();
                fixAccountThread4._BullhornListInfo = _BullhornListInfo;
                fixAccountThread4.FixManagerObj = FixManagerObj;
                accountThread4 = new Thread(new ThreadStart(fixAccountThread4.FixAccount));
                accountThread4.IsBackground = true;
                accountThread4.Start();

                //5
                FixAccountThread fixAccountThread5 = new FixAccountThread();
                fixAccountThread5._BullhornListInfo = _BullhornListInfo;
                fixAccountThread5.FixManagerObj = FixManagerObj;
                accountThread5 = new Thread(new ThreadStart(fixAccountThread5.FixAccount));
                accountThread5.IsBackground = true;
                accountThread5.Start();

                //6
                FixAccountThread fixAccountThread6 = new FixAccountThread();
                fixAccountThread6._BullhornListInfo = _BullhornListInfo;
                fixAccountThread6.FixManagerObj = FixManagerObj;
                accountThread6 = new Thread(new ThreadStart(fixAccountThread6.FixAccount));
                accountThread6.IsBackground = true;
                accountThread6.Start();

                //7
                FixAccountThread fixAccountThread7 = new FixAccountThread();
                fixAccountThread7._BullhornListInfo = _BullhornListInfo;
                fixAccountThread7.FixManagerObj = FixManagerObj;
                accountThread7 = new Thread(new ThreadStart(fixAccountThread7.FixAccount));
                accountThread7.IsBackground = true;
                accountThread7.Start();

                //8
                FixAccountThread fixAccountThread8 = new FixAccountThread();
                fixAccountThread8._BullhornListInfo = _BullhornListInfo;
                fixAccountThread8.FixManagerObj = FixManagerObj;
                accountThread8 = new Thread(new ThreadStart(fixAccountThread8.FixAccount));
                accountThread8.IsBackground = true;
                accountThread8.Start();

                //9
                FixAccountThread fixAccountThread9 = new FixAccountThread();
                fixAccountThread9._BullhornListInfo = _BullhornListInfo;
                fixAccountThread9.FixManagerObj = FixManagerObj;
                accountThread9 = new Thread(new ThreadStart(fixAccountThread9.FixAccount));
                accountThread9.IsBackground = true;
                accountThread9.Start();

                //10
                FixAccountThread fixAccountThread10 = new FixAccountThread();
                fixAccountThread10._BullhornListInfo = _BullhornListInfo;
                fixAccountThread10.FixManagerObj = FixManagerObj;
                accountThread10 = new Thread(new ThreadStart(fixAccountThread10.FixAccount));
                accountThread10.IsBackground = true;
                accountThread10.Start();

                accountThread1.Join();
                accountThread2.Join();
                accountThread3.Join();
                accountThread4.Join();
                accountThread5.Join();
                accountThread6.Join();
                accountThread7.Join();
                accountThread8.Join();
                accountThread9.Join();
                accountThread10.Join();


                if (FixManagerObj.FixListStop != null)
                {

                    FixManagerObj.FixListStop(FixManagerObj, new FixEventArgs() { BullhornListInfoObj = _BullhornListInfo });
                }
            }
        }

        class FixAccountThread
        {
            private BullhornService _threadBullhornService;
            public BullhornListInfo _BullhornListInfo { get; set; }
            public FixManager FixManagerObj { get; set; }
            private static Object _lockObj = new Object();

            public void FixAccount()
            {
                _threadBullhornService = new BullhornService(_BullhornListInfo.BullhornAccountFixInfoObj.BullhornAccount.UserName,
                    _BullhornListInfo.BullhornAccountFixInfoObj.BullhornAccount.Password,
                    _BullhornListInfo.BullhornAccountFixInfoObj.BullhornAccount.ApiKey, false);

                while (true)
                {
                    KeyValuePair<int, ClientContactInfo> clientContactInfoDictItem;
                    lock (_lockObj)
                    {
                        var queryClientContactInfo = from x in _BullhornListInfo.ClientContactInfoDict
                                                     where x.Value.State == FixState.NotFixed
                                                     select x;
                        clientContactInfoDictItem = queryClientContactInfo.ToList().FirstOrDefault();
                    }

                    if (clientContactInfoDictItem.Value == null)
                    {
                        return;
                    }

                    //fix the client contact
                    var tryCount = 0;

                    int clientContactId = clientContactInfoDictItem.Key;
                    ClientContactInfo clientContactInfo = clientContactInfoDictItem.Value;
                    clientContactInfo.State = FixState.Fixing;
                    while (true)
                    {
                        tryCount++;
                        try
                        {
                            var clientContact = _threadBullhornService.GetClientContact(clientContactId);
                            clientContactInfo.ClientContact = clientContact;

                            if (clientContact == null)
                            {
                                clientContactInfo.State = FixState.Failed;
                                clientContactInfo.Message = "Cannot find the client contact with id " + clientContactId;
                                if (FixManagerObj.FixContactFail != null)
                                {
                                    FixManagerObj.FixContactFail(FixManagerObj, new FixEventArgs() { BullhornListInfoObj = _BullhornListInfo });
                                }
                                break;

                            }

                            //Restore
                            var foundEmailInfo =
                                FixManagerObj._emailInfos.FirstOrDefault(x => x.FirstName == clientContact.firstName
                                && x.LastName == clientContact.lastName && x.FixedEmail == clientContact.email && x.ListName == _BullhornListInfo.DistributionList.name);
                            if (foundEmailInfo != null)
                            {
                                String prevEmail = clientContact.email;
                                clientContact.email = foundEmailInfo.OrgEmail;
                                clientContactDto result = _threadBullhornService.SaveClientContact(clientContact);
                                clientContactInfo.FixedEmail = clientContact.email;
                                clientContactInfo.State = FixState.Fixed;
                                clientContactInfo.Message = "Fixed";
                                clientContact.email = prevEmail;
                                if (FixManagerObj.FixContactSuccess != null)
                                {
                                    FixManagerObj.FixContactSuccess(FixManagerObj, new FixEventArgs() { BullhornListInfoObj = _BullhornListInfo });
                                }
                            }
                            else
                            {
                                //do not sync
                                clientContactInfo.State = FixState.Ignored;
                                clientContactInfo.Message = "Ignored";
                                if (FixManagerObj.FixContactIgnore != null)
                                {
                                    FixManagerObj.FixContactIgnore(FixManagerObj, new FixEventArgs() { BullhornListInfoObj = _BullhornListInfo });
                                }
                                break;

                            }

                            
                            
                            break;
                        }
                        catch (Exception ex)
                        {
                            if (tryCount > maxTry)
                            {
                                clientContactInfo.State = FixState.Failed;
                                clientContactInfo.Message = ex.Message;
                                if (FixManagerObj.FixContactFail != null)
                                {
                                    FixManagerObj.FixContactFail(FixManagerObj, new FixEventArgs("Cannot fix: " + ex.StackTrace) { BullhornListInfoObj = _BullhornListInfo });
                                }
                                break;
                            }
                        }

                    }

                    //todo: need to research why some contacts is still in Syncing state!!!!!!!
                    if (clientContactInfo.State == FixState.Fixing)
                    {
                        clientContactInfo.State = FixState.NotFixed;
                        clientContactInfo.Message = "Pending";
                        clientContactInfo.ClientContact = null;
                    }
                }

            }
        }



    }
}
